import datetime
import copy
import pymongo
import numpy as np
import Core.Gadget as Gadget
import Core.Algorithm as Algo
import Core.IO as IO
import Core.DataSeries as DataSerie
import SystematicFactors.General

def ExcessReturn_Probability(database, realtime,
                             datetime1, datetime2,
                             lag_days=20,
                             instruments=None, benchmark_symbol="000300.SH"):
    # ---Instrument Data---
    instrument_data = database.Find("Instruments", "Stock")
    df_instruments = Gadget.DocumentsToDataFrame(instrument_data,
                                                 keep=["symbol", "datetime1", "datetime2"],
                                                 rename={"symbol":"Symbol", "datetime1":"DateTime1", "datetime2":"DateTime2"})
    df_instruments["DateTime1"] = df_instruments["DateTime1"].dt.date
    df_instruments["DateTime2"] = df_instruments["DateTime2"].dt.date
    print(df_instruments.head())

    # ---Benchmark Data---
    benchmark_series = database.Find("DailyBar", "Index", {"Symbol": benchmark_symbol})
    df_benchmark = Gadget.DocumentsToDataFrame(benchmark_series,
                                               keep=["date", "close"],
                                               rename={"date":"Date", "close":"Close"})
    df_benchmark["Return20"] = df_benchmark["Close"] / df_benchmark["Close"].shift(lag_days) - 1
    df_benchmark["DateLag20"] = df_benchmark["Date"].shift(lag_days)

    #
    new_documents = []
    # ---Loop Date---
    for index, value in df_benchmark.iterrows():
        current_date = value["Date"]
        benchmark_return = value["Return20"]
        if current_date < datetime1.date():
            continue
        if current_date > datetime2.date():
            continue

        # 确定时间日期
        begin_date = value["DateLag20"]

        # 确定Instruments
        # 上市时间早于一年前 ,当前没有退市
        yearago_date = begin_date + datetime.timedelta(-365)
        df_instruments_listed = df_instruments[(df_instruments["DateTime1"] <= yearago_date) & (df_instruments["DateTime2"] >= current_date)]
        instruments_listed = list(df_instruments_listed["Symbol"])

        # 计算收益状况
        symbols_noQuote = []
        symbols_noTrade = []
        symbols_normal = []
        documents = []
        tmp_count1 = 0
        tmp_count2 = 0
        for symbol in instruments_listed:
            doc = {}
            doc["Symbol"] = symbol
            doc["RangeReturn"] = np.nan
            doc["Status"] = None

            key1 = symbol + "_" + Gadget.ToDateString(begin_date)
            key2 = symbol + "_" + Gadget.ToDateString(current_date)
            #
            quote1 = realtime.GetHashDocument("DailyBar", key1)
            quote2 = realtime.GetHashDocument("DailyBar", key2)
            if quote1 == None or quote2 == None:
                print("Missing Quote", current_date, symbol)
                special_symbls = []
                if symbol in special_symbls:
                    pass
                else:
                    pass
                doc["RangeReturn"] = np.nan
                tmp_count2 += 1
            else:
                doc["RangeReturn"] = quote2["BClose"] / quote1["BClose"] - 1
            #
            tmp_count1 += 1
            documents.append(doc)

        # ---统计结果---
        df_result = Gadget.DocumentsToDataFrame(documents)
        df_result["ExcessReturn"] = df_result["RangeReturn"] - benchmark_return
        count_total = df_result.shape[0]
        count_invalid = df_result["RangeReturn"].isnull().sum()
        count_valid = count_total - count_invalid
        count_winMarket = df_result[df_result["ExcessReturn"] > 0].shape[0]
        count_loseMarket = df_result[df_result["ExcessReturn"] <= 0].shape[0]
        #
        winning_ratio = count_winMarket / count_valid # 战胜市场概率
        expect_total = df_result[df_result["RangeReturn"] != np.nan]["RangeReturn"].mean()
        expect_win = df_result[df_result["ExcessReturn"] > 0]["RangeReturn"].mean()
        expect_lose = df_result[df_result["ExcessReturn"] <= 0]["RangeReturn"].mean()
        #
        print(current_date, "Total#", count_total, "Valid", count_valid, "Win", count_winMarket, "Lose", count_loseMarket, "Ratio", winning_ratio)
        print(current_date, "Total%", expect_total, "Win", expect_win, "Lose", expect_lose)

        # ---20vs80 gap---
        # ---ReturnGap2080_20D_TotalA
        df_result.sort_values(by="RangeReturn", ascending=False, inplace=True)
        p20 = int(0.2 * count_valid)
        df_top = df_result[:p20]
        df_bot = df_result[p20:]
        # print(df_top)
        # print(df_bot)
        gap_topbot = df_top["RangeReturn"].mean() - df_bot["RangeReturn"].mean()

        # ---RangeReturn Volatility---
        sample_volatility = df_result["RangeReturn"].std()

        #
        print(current_date, "Gap2080", gap_topbot, "SampleVolatility", sample_volatility)

        # ---Generate Documents---
        new_document = {"Date": current_date}
        new_document["WinRatio"] = winning_ratio
        new_document["TotalCount"] = count_total
        new_document["WinCount"] = count_winMarket
        new_document["LoseCount"] = count_loseMarket
        new_document["TotalExpect"] = expect_total
        new_document["WinExpect"] = expect_win
        new_document["LoseExpect"] = expect_lose
        new_document["ReturnGap"] = gap_topbot
        new_document["ReturnVolatility"] = sample_volatility
        new_documents.append(new_document)
        a = 0
    #
    df = Gadget.DocumentsToDataFrame(new_documents)
    return df


def HS300vsMarket_ReturnGap(database, realtime, datetime1, datetime2, benchmark_symbol="000300.SH"):
    # ---InstrumentList---
    instrument_list = database.Find("Instruments", "InstrumentList", {"InstrumentList": benchmark_symbol})
    df_instrument_list = Gadget.DocumentsToDataFrame(instrument_list, keep=["Date", "Symbol"])
    df_instrument_list_update_date = df_instrument_list.drop_duplicates(['Date'])

    print(df_instrument_list_update_date)


    # ---Instrument Data---
    instrument_data = database.Find("Instruments", "Stock")
    df_instruments = Gadget.DocumentsToDataFrame(instrument_data, keep=["Symbol", "DateTime1", "DateTime2"])
    df_instruments["DateTime1"] = df_instruments["DateTime1"].dt.date
    df_instruments["DateTime2"] = df_instruments["DateTime2"].dt.date
    print(df_instruments.head())

    # ---Benchmark Data---
    benchmark_series = database.Find("DailyBar", "Index", {"Symbol": benchmark_symbol})
    df_benchmark = Gadget.DocumentsToDataFrame(benchmark_series, keep=["Date", "Close"])
    df_benchmark["BenchmarkReturn"] = df_benchmark["Close"] / df_benchmark["Close"].shift(1) - 1
    df_benchmark["DateLag1"] = df_benchmark["Date"].shift(1)

    #
    new_documents = []
    # ---Loop Date---
    for index, value in df_benchmark.iterrows():
        current_date = value["Date"]
        benchmark_return = value["Return20"]
        if current_date < datetime1.date():
            continue
        if current_date > datetime2.date():
            continue

        # 确定时间日期
        begin_date = value["DateLag1"]

        # 确定Instruments
        # 上市时间早于一年前 ,当前没有退市
        yearago_date = begin_date + datetime.timedelta(-365)
        df_instruments_listed = df_instruments[
            (df_instruments["DateTime1"] <= yearago_date) & (df_instruments["DateTime2"] >= current_date)]
        instruments_listed = list(df_instruments_listed["Symbol"])

        #


        # 计算收益状况
        symbols_noQuote = []
        symbols_noTrade = []
        symbols_normal = []
        documents = []
        tmp_count1 = 0
        tmp_count2 = 0
        for symbol in instruments_listed:
            doc = {}
            doc["Symbol"] = symbol
            doc["RangeReturn"] = np.nan
            doc["Status"] = None

            key1 = symbol + "_" + Gadget.ToDateString(begin_date)
            key2 = symbol + "_" + Gadget.ToDateString(current_date)
            #
            quote1 = realtime.GetHashDocument("DailyBar", key1)
            quote2 = realtime.GetHashDocument("DailyBar", key2)
            if quote1 == None or quote2 == None:
                print("Missing Quote", current_date, symbol)
                special_symbls = []
                if symbol in special_symbls:
                    pass
                else:
                    pass
                doc["RangeReturn"] = np.nan
                tmp_count2 += 1
            else:
                doc["RangeReturn"] = quote2["BClose"] / quote1["BClose"] - 1
            #
            tmp_count1 += 1
            documents.append(doc)

        # ---统计结果---
        df_result = Gadget.DocumentsToDataFrame(documents)


def Calculate_ReturnStructure(database, realtime, datetime1, datetime2):
    #
    df = ExcessReturn_Probability(database, realtime,
                                  datetime1, datetime2,
                                  benchmark_symbol="000300.SH")
    #
    SystematicFactors.General.SaveSystematic_MarketFactorToDatabase(database, df,
                                                                    factorName="BeatMarketRatio_20D_000300.SH",
                                                                    fieldName="WinRatio")

    SystematicFactors.General.SaveSystematic_MarketFactorToDatabase(database, df,
                                                                    factorName="ReturnMean_20D_TotalA",
                                                                    fieldName="TotalExpect")

    SystematicFactors.General.SaveSystematic_MarketFactorToDatabase(database, df,
                                                                    factorName="ReturnVolatility_20D_TotalA",
                                                                    fieldName="ReturnVolatility")

    SystematicFactors.General.SaveSystematic_MarketFactorToDatabase(database, df,
                                                                    factorName="ReturnGap20vs80_20D_TotalA",
                                                                    fieldName="ReturnGap")


if __name__ == '__main__':
    #
    from Core.Config import *
    pathfilename = os.getcwd() + "\..\Config\config2.json"
    config = Config(pathfilename)
    database = config.DataBase("JDMySQL")
    realtime = config.RealTime()

    datetime1 = datetime.datetime(2010, 1, 1)
    datetime2 = datetime.datetime(2010, 2, 1)
    # HS300vsMarket_ReturnGap(database, realtime, datetime1, datetime2, benchmark_symbol="000300.SH")

    # ---DateTime---
    datetime2 = datetime.datetime.now()
    datetime1 = datetime2 + datetime.timedelta(days=-10)
    Calculate_ReturnStructure(database, realtime, datetime1, datetime2)
